﻿/*
 *Author: Jeff Liu 
 *
 *Under MIT License
 *jebberwocky@gmail.com
 */

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using CtpGglMap.Impl;
using CtpGglMap.Util;

namespace CtpGglMap.Plus
{
    public class GBoundsWithGmarkers
    {
        List<IMapItem> gmarker;
        GBounds bounds;

        public GMarker CenterMarker
        {
            set;
            get;
        }

        public GBoundsWithGmarkers(List<IMapItem> markers):this()
        {
            this.gmarker = markers;
        }

        public GBoundsWithGmarkers()
        {
            if(gmarker!=null)
             bounds = new GBounds(gmarker);
        }

        public void AddMarker(GMarker marker)
        {
            if (gmarker == null)
            {
                gmarker = new List<IMapItem>();
            }
            gmarker.Add(marker);
            bounds = new GBounds(gmarker);
        }

        public List<IMapItem> GMarkers
        {
            get
            {
                return gmarker;
            }
        }

        public GeoPoint Center
        {
            get
            {
                return (bounds == null) ? GeoPointImpl.UNDEFINED : bounds.Center;
            }
        }
    }

    public class DistanceCluster: ICluster
    {
        IMap _map;

        List<GBoundsWithGmarkers> bounds = null;

        private double distance = 20.0;

        public IMap Map
        {
            get
            {
                return _map;
            }
            set
            {
                _map = value;
            }
        }

        public DistanceCluster(double distance)
        {
            this.bounds = new List<GBoundsWithGmarkers>();
            this.distance = distance;
        }

        private void clean()
        {
            this.bounds = new List<GBoundsWithGmarkers>();
        }

        private void clustering()
        {
            clean();
            if (_map == null && _map.GetType() == typeof(StaticGMap))
                return;
            foreach (IMapItem item in ((StaticGMap)_map).GetItems())
            {
                if (item.GetType() == typeof(GMarker))
                {
                    GMarker marker = (GMarker)item;
                    GBoundsWithGmarkers gwg = null;
                    foreach (GBoundsWithGmarkers bound in this.bounds)
                    {
                        int __d = GeoUtil.CalculateDistance(bound.Center, marker.Point, _map);
                        Console.WriteLine("distance from bound to marker:" + marker.Label + " is " + __d);
                        if (__d <= distance)
                        {
                            gwg = bound;
                            break;
                        }
                    }
                    if (gwg == null)
                    {
                        gwg = new GBoundsWithGmarkers();
                        gwg.AddMarker(marker);
                        bounds.Add(gwg);
                    }
                    else
                    {
                        gwg.AddMarker(marker);
                    }
                }
            }
        }

        public string GetShortenUrl()
        {
            StringBuilder sb = new StringBuilder(CtpGglMap.Core.StaticMap.Const.GOOGLE_STATIC_MAPS_API_URL + "?");
            if (_map != null &&
               (_map.GetType().IsSubclassOf(typeof(CtpGglMap.Impl.StaticGMap)) || _map.GetType() == typeof(CtpGglMap.Impl.StaticGMap))
               )
            {
                StaticGMap gmap = (StaticGMap)_map;
                //if "implicit positioning," calculate the center & zoom level from map items
                if (gmap.AutoFit)
                {
                    gmap.Center = GeoUtil.CalculateCenterFromMapItem(gmap.GetItems());
                    gmap.Zoom = GeoUtil.ZoomToFit(gmap, gmap.GetItems(), gmap.ZoomDelta);
                }
                //do clustering first
                this.clustering();
                //using clustered markers instead of the ones in map

                //build up parameters
                List<String> param = new List<string>();
                if (gmap.Center != null)
                {
                    param.Add(string.Format("center={0},{1}", gmap.Center.Lat, gmap.Center.Lng));
                }
                else
                {
                    return null;
                }
                param.Add("zoom=" + gmap.Zoom);
                param.Add(String.Format("size={0}x{1}", gmap.Width, gmap.Height));
                if (!String.IsNullOrEmpty(gmap.MapType))
                    param.Add("maptype=" + gmap.MapType);
                param.Add("sensor=" + gmap.Sensor.ToString().ToLower());
                //show Markers Path or not
                List<GeoPoint> markersPoints = new List<GeoPoint>();

                foreach (IMapItem item in gmap.GetItems())
                {
                    if (item != null)
                    {
                        if (item.GetType() == typeof(GMarker) || item.GetType().IsSubclassOf(typeof(GMarker)))
                        {
                            //use the clustered marker instead of ones in map
                        }
                        else if (item.GetType() == typeof(GPath))
                        {
                            GPath path = item as GPath;
                            param.Add("path=" + path.GetUrl());
                        }
                    }
                }
                //clustered markers
                int count = 1;
                foreach (GBoundsWithGmarkers gwg in this.bounds)
                {
                    if (gwg != null)
                    {
                        GMarker marker = null;
                        if (gwg.GMarkers.Count > 1)
                        {
                            //use the central position
                            marker = new GMarker();
                            marker.Point = gwg.Center;
                            marker.Color = "blue";
                            marker.Label = count.ToString();
                            gwg.CenterMarker = marker;
                        }
                        else
                        {
                            marker = (GMarker)gwg.GMarkers[0];
                        }
                        param.Add("markers=" + marker.GetUrl());
                    }
                    count++;
                }
                if (gmap.ShowMarkersPath)
                {
                    GPath path = new GPath(markersPoints);
                    path.Weight = gmap.MarkersPathWeight;
                    path.Color = gmap.MarkersPathColor;
                    param.Add("path=" + path.GetUrl());
                }
                //Stringify
                for (int i = 0; i < param.Count; i++)
                {
                    sb.Append(param[i]);
                    if (i < param.Count - 1)
                        sb.Append("&");
                }
            }
            String v = sb.ToString();
            CtpGglMap.Util.Common.DEBUG(v);
            return v;
        }

        public List<IMapItem> VisibleItems
        {
            get { throw new NotImplementedException(); }
        }

        public List<IMapItem> InvisibleItems
        {
            get { throw new NotImplementedException(); }
        }
    }
}
